home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / javax / swing / UIManager.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  29.5 KB  |  918 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)UIManager.java    1.68 98/08/28
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14. package javax.swing;
  15.  
  16. import java.awt.Container;
  17. import java.awt.Window;
  18. import java.awt.Font;
  19. import java.awt.Color;
  20. import java.awt.Insets;
  21. import java.awt.Dimension;
  22.  
  23. import javax.swing.plaf.ComponentUI;
  24. import javax.swing.border.Border;
  25.  
  26. import javax.swing.event.SwingPropertyChangeSupport;
  27. import java.beans.PropertyChangeListener;
  28. import java.beans.PropertyChangeEvent;
  29.  
  30. import java.io.FileOutputStream;
  31. import java.io.IOException;
  32. import java.io.ObjectOutputStream;
  33. import java.io.ObjectInputStream;
  34. import java.io.Serializable;
  35. import java.io.File;
  36. import java.io.FileInputStream;
  37. import java.io.BufferedInputStream;
  38.  
  39. import java.util.Enumeration;
  40. import java.util.Hashtable;
  41. import java.util.Properties;
  42. import java.util.StringTokenizer;
  43. import java.util.Vector;
  44.  
  45.  
  46. /**
  47.  * This class keeps track of the current look and feel and its
  48.  * defaults.
  49.  * <p>
  50.  * We manage three levels of defaults: user defaults, look
  51.  * and feel defaults, system defaults.  A call to UIManager.get()
  52.  * checks all three levels in order and returns the first non-null 
  53.  * value for a key, if any.  A call to UIManager.put() just
  54.  * affects the user defaults.  Note that a call to 
  55.  * setLookAndFeel() doesn't affect the user defaults, it just
  56.  * replaces the middle defaults "level".
  57.  * <p>
  58.  * <strong>Warning:</strong>
  59.  * Serialized objects of this class will not be compatible with 
  60.  * future Swing releases.  The current serialization support is appropriate
  61.  * for short term storage or RMI between applications running the same
  62.  * version of Swing.  A future release of Swing will provide support for
  63.  * long term persistence.
  64.  *
  65.  * @version 1.68 08/28/98
  66.  * @author Thomas Ball
  67.  * @author Hans Muller
  68.  */
  69. public class UIManager implements Serializable 
  70. {
  71.     /**
  72.      * This class defines the state managed by the UIManager.  For 
  73.      * Swing applications the fields in this class could just as well
  74.      * be static members of UIManager however we give them "AppContext"
  75.      * scope instead so that applets (and potentially multiple lightweight
  76.      * applications running in a single VM) have their own state. For 
  77.      * example an applet can it's look and feel, see setLookAndFeel().
  78.      * Doing so has no affect on other applets (or the browser).
  79.      */
  80.     private static class LAFState 
  81.     {
  82.         Properties swingProps;
  83.         private UIDefaults[] tables = new UIDefaults[2];
  84.  
  85.         boolean initialized = false;
  86.         MultiUIDefaults multiUIDefaults = new MultiUIDefaults(tables);
  87.         LookAndFeel lookAndFeel;
  88.         LookAndFeel multiLookAndFeel = null;
  89.         Vector auxLookAndFeels = null;
  90.         SwingPropertyChangeSupport changeSupport = 
  91.             new SwingPropertyChangeSupport(UIManager.class);
  92.  
  93.         UIDefaults getLookAndFeelDefaults() { return tables[0]; }
  94.         void setLookAndFeelDefaults(UIDefaults x) { tables[0] = x; }
  95.  
  96.         UIDefaults getSystemDefaults() { return tables[1]; }
  97.         void setSystemDefaults(UIDefaults x) { tables[1] = x; }
  98.     }
  99.  
  100.  
  101.     /**
  102.      * The AppContext key for our one LAFState instance.
  103.      */
  104.     private static final Object lafStateACKey = new StringBuffer("LookAndFeel State");
  105.  
  106.  
  107.     /**
  108.      * Return the LAFState object, lazily create one if neccessary.  All access
  109.      * to the LAFState fields is done via this method, e.g.:
  110.      * <pre>
  111.      *     getLAFState().initialized = true;
  112.      * </pre>
  113.      */
  114.     private static LAFState getLAFState() {
  115.         LAFState rv = (LAFState)SwingUtilities.appContextGet(lafStateACKey);
  116.         if (rv != null) {
  117.             return rv;
  118.         }
  119.         synchronized(UIManager.class) {
  120.             rv = (LAFState)SwingUtilities.appContextGet(lafStateACKey);
  121.             if (rv != null) {
  122.                 return rv;
  123.             }
  124.             SwingUtilities.appContextPut(lafStateACKey, (rv = new LAFState()));
  125.             return rv;
  126.         }
  127.     }
  128.  
  129.  
  130.     /* Keys used for the properties file in <java.home>/lib/swing.properties.
  131.      * See loadUserProperties(), initialize().
  132.      */
  133.  
  134.     private static final String defaultLAFKey = "swing.defaultlaf";
  135.     private static final String auxiliaryLAFsKey = "swing.auxiliarylaf";
  136.     private static final String multiplexingLAFKey = "swing.plaf.multiplexinglaf";
  137.     private static final String installedLAFsKey = "swing.installedlafs";
  138.  
  139.     /**
  140.      * Return a swing.properties file key for the attribute of specified 
  141.      * look and feel.  The attr is either "name" or "class", a typical
  142.      * key would be: "swing.installedlaf.windows.name"
  143.      */
  144.     private static String makeInstalledLAFKey(String laf, String attr) {
  145.         return "swing.installedlaf." + laf + "." + attr;
  146.     }
  147.  
  148.     /**
  149.      * The filename for swing.properties is a path like this (Unix version):
  150.      * <java.home>/lib/swing.properties.  This method returns a bogus
  151.      * filename if java.home isn't defined.  
  152.      */
  153.     private static String makeSwingPropertiesFilename() {
  154.         final String homeDir[] = new String[]{"<java.home undefined>"};
  155.     SwingUtilities.doPrivileged(new Runnable() {
  156.         public void run() {
  157.         homeDir[0] = System.getProperty("java.home", "<java.home undefined>");
  158.         }
  159.     });
  160.         String sep = File.separator;
  161.         return homeDir[0] + sep + "lib" + sep + "swing.properties";
  162.     }
  163.  
  164.  
  165.     /** 
  166.      * Provide a little information about an installed LookAndFeel
  167.      * for the sake of configuring a menu or for initial application 
  168.      * set up.
  169.      * 
  170.      * @see UIManager#getInstalledLookAndFeels
  171.      * @see LookAndFeel
  172.      */
  173.     public static class LookAndFeelInfo {
  174.         private String name;
  175.         private String className;
  176.  
  177.         /**
  178.          * Constructs an UIManager$LookAndFeelInfo object.
  179.          *
  180.          * @param name      a String specifying the name of the look and feel
  181.          * @param className a String specifiying the name of the class that
  182.          *                  implements the look and feel
  183.          */
  184.         public LookAndFeelInfo(String name, String className) {
  185.             this.name = name;
  186.             this.className = className;
  187.         }
  188.  
  189.         /**
  190.          * Returns the name of the look and feel in a form suitable
  191.          * for a menu or other presentation
  192.          * @return a String containing the name
  193.          * @see LookAndFeel#getName
  194.          */
  195.         public String getName() {
  196.             return name;
  197.         }
  198.  
  199.         /**
  200.          * Returns the name of the class that implements this look and feel.
  201.          * @return the name of the class that implements this LookAndFeel
  202.          * @see LookAndFeel
  203.          */
  204.         public String getClassName() {
  205.             return className;
  206.         }
  207.  
  208.         /**
  209.          * Returns a string that displays and identifies this
  210.          * object's properties.
  211.          *
  212.          * @return a String representation of this object
  213.          */
  214.         public String toString() {
  215.             return getClass().getName() + "[" + getName() + " " + getClassName() + "]";
  216.         }
  217.     }
  218.  
  219.  
  220.     /**
  221.      * The default value of installedLAFS is used when no swing.properties
  222.      * file is available or if the file doesn't contain a "swing.installedlafs"
  223.      * property.   
  224.      * 
  225.      * @see #initializeInstalledLAFs
  226.      */
  227.     private static LookAndFeelInfo[] installedLAFs = {
  228.         new LookAndFeelInfo("Metal", "javax.swing.plaf.metal.MetalLookAndFeel"),
  229.         new LookAndFeelInfo("CDE/Motif", "com.sun.java.swing.plaf.motif.MotifLookAndFeel"),
  230.         new LookAndFeelInfo("Windows", "com.sun.java.swing.plaf.windows.WindowsLookAndFeel")
  231.     };
  232.  
  233.  
  234.     /** 
  235.      * Return an array of objects that provide some information about the
  236.      * LookAndFeel implementations that have been installed with this 
  237.      * java development kit.  The LookAndFeel info objects can be used
  238.      * by an application to construct a menu of look and feel options for 
  239.      * the user or to set the look and feel at start up time.  Note that 
  240.      * we do not return the LookAndFeel classes themselves here to avoid the
  241.      * cost of unnecessarily loading them.
  242.      * <p>
  243.      * Given a LookAndFeelInfo object one can set the current look and feel
  244.      * like this:
  245.      * <pre>
  246.      * UIManager.setLookAndFeel(info.getClassName());
  247.      * </pre>
  248.      * 
  249.      * @see #setLookAndFeel
  250.      */
  251.     public static LookAndFeelInfo[] getInstalledLookAndFeels() {
  252.         maybeInitialize();
  253.         LookAndFeelInfo[] ilafs = installedLAFs;
  254.         LookAndFeelInfo[] rv = new LookAndFeelInfo[ilafs.length];
  255.         System.arraycopy(ilafs, 0, rv, 0, ilafs.length);
  256.         return rv;
  257.     }
  258.  
  259.  
  260.     /**
  261.      * Replaces the current array of installed LookAndFeelInfos.
  262.      * 
  263.      * @see #getInstalledLookAndFeels
  264.      */
  265.     public static void setInstalledLookAndFeels(LookAndFeelInfo[] infos)
  266.         throws SecurityException
  267.     {
  268.         LookAndFeelInfo[] newInfos = new LookAndFeelInfo[infos.length];
  269.         System.arraycopy(infos, 0, newInfos, 0, infos.length);
  270.         installedLAFs = newInfos;
  271.     }
  272.  
  273.  
  274.     /**
  275.      * Adds the specified look and feel to the current array and
  276.      * then calls {@link #setInstalledLookAndFeels}.
  277.      * @param info a LookAndFeelInfo object that names the look and feel
  278.      *        and identifies that class that implements it
  279.      */
  280.     public static void installLookAndFeel(LookAndFeelInfo info) {
  281.         LookAndFeelInfo[] infos = getInstalledLookAndFeels();
  282.         LookAndFeelInfo[] newInfos = new LookAndFeelInfo[infos.length + 1];
  283.         System.arraycopy(infos, 0, newInfos, 0, infos.length);
  284.         newInfos[infos.length] = info;
  285.         setInstalledLookAndFeels(newInfos);
  286.     }
  287.  
  288.  
  289.     /**
  290.      * Creates a new look and feel and adds it to the current array.
  291.      * Then calls {@link #setInstalledLookAndFeels}.
  292.      *
  293.      * @param name       a String specifying the name of the look and feel
  294.      * @param className  a String specifying the class name that implements the
  295.      *                   look and feel
  296.      */
  297.     public static void installLookAndFeel(String name, String className) {
  298.         installLookAndFeel(new LookAndFeelInfo(name, className));
  299.     }
  300.  
  301.  
  302.     /**
  303.      * Returns The current default look and feel, or null.
  304.      *
  305.      * @return The current default look and feel, or null.
  306.      * @see #setLookAndFeel
  307.      */
  308.     public static LookAndFeel getLookAndFeel() {
  309.         maybeInitialize();
  310.         return getLAFState().lookAndFeel;
  311.     }
  312.     
  313.  
  314.     /**
  315.      * Set the current default look and feel using a LookAndFeel object.  
  316.      * <p>
  317.      * This is a JavaBeans bound property.
  318.      *
  319.      * @param newLookAndFeel the LookAndFeel object
  320.      * @exception UnsupportedLookAndFeelException If <code>lnf.isSupportedLookAndFeel()</code> is false.
  321.      * @see #getLookAndFeel
  322.      */
  323.     public static void setLookAndFeel(LookAndFeel newLookAndFeel) 
  324.         throws UnsupportedLookAndFeelException 
  325.     {
  326.         if ((newLookAndFeel != null) && !newLookAndFeel.isSupportedLookAndFeel()) {
  327.             String s = newLookAndFeel.toString() + " not supported on this platform";
  328.             throw new UnsupportedLookAndFeelException(s);
  329.         }
  330.  
  331.         LookAndFeel oldLookAndFeel = getLAFState().lookAndFeel;
  332.         if (oldLookAndFeel != null) {
  333.             oldLookAndFeel.uninitialize();
  334.         }
  335.  
  336.         getLAFState().lookAndFeel = newLookAndFeel;
  337.         if (newLookAndFeel != null) {
  338.             newLookAndFeel.initialize();
  339.             getLAFState().setLookAndFeelDefaults(newLookAndFeel.getDefaults());
  340.         }
  341.         else {
  342.             getLAFState().setLookAndFeelDefaults(null);
  343.         }
  344.  
  345.         getLAFState().changeSupport.firePropertyChange("lookAndFeel", oldLookAndFeel, newLookAndFeel);
  346.     }
  347.  
  348.     
  349.     /**
  350.      * Set the current default look and feel using a class name.
  351.      *
  352.      * @param className  a string specifying the name of the class that implements
  353.      *        the look and feel
  354.      * @exception ClassNotFoundException If the LookAndFeel class could not be found.
  355.      * @exception InstantiationException If a new instance of the class couldn't be creatd.
  356.      * @exception IllegalAccessException If the class or initializer isn't accessible. 
  357.      * @exception UnsupportedLookAndFeelException If <code>lnf.isSupportedLookAndFeel()</code> is false.
  358.      */
  359.     public static void setLookAndFeel(String className) 
  360.         throws ClassNotFoundException, 
  361.                InstantiationException, 
  362.                IllegalAccessException,
  363.                UnsupportedLookAndFeelException 
  364.     {
  365.             Class lnfClass = Class.forName(className);
  366.             setLookAndFeel((LookAndFeel)(lnfClass.newInstance()));
  367.     }
  368.  
  369.  
  370.     /**
  371.      * Returns the name of the LookAndFeel class that implements
  372.      * the native systems look and feel if there is one,
  373.      * otherwise the name of the default cross platform LookAndFeel
  374.      * class.
  375.      * 
  376.      * @see #setLookAndFeel
  377.      * @see #getCrossPlatformLookAndFeelClassName
  378.      */
  379.     public static String getSystemLookAndFeelClassName() {
  380.         final String osName[] = new String[]{""};
  381.     SwingUtilities.doPrivileged(new Runnable() {
  382.         public void run() {
  383.         osName[0] = System.getProperty("os.name");
  384.         }
  385.     });
  386.  
  387.         if (osName[0] != null) {
  388.             if (osName[0].indexOf("Windows") != -1) {
  389.                 return "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
  390.             }
  391.             else if ((osName[0].indexOf("Solaris") != -1) || 
  392.              (osName[0].indexOf("SunOS") != -1)) {
  393.                 return "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
  394.             } 
  395.         else if (osName[0].indexOf("Mac") != -1 ) {
  396.                 return "javax.swing.plaf.mac.MacLookAndFeel";
  397.             }
  398.         }
  399.         return getCrossPlatformLookAndFeelClassName();
  400.     }
  401.  
  402.  
  403.     /**
  404.      * Returns the name of the LookAndFeel class that implements
  405.      * the default cross platform look and feel, i.e. the "Java
  406.      * Look and Feel", or JLF.
  407.      * 
  408.      * @return  a string with the JLF implementation-class
  409.      * @see #setLookAndFeel
  410.      * @see #getSystemLookAndFeelClassName
  411.      */
  412.     public static String getCrossPlatformLookAndFeelClassName() {
  413.         return "javax.swing.plaf.metal.MetalLookAndFeel";
  414.     }
  415.  
  416.  
  417.     /**
  418.      * Returns the default values for this look and feel.
  419.      *
  420.      * @return an UIDefaults object containing the default values
  421.      */
  422.     public static UIDefaults getDefaults() {
  423.         maybeInitialize();
  424.         return getLAFState().multiUIDefaults;
  425.     }
  426.     
  427.     /**
  428.      * Returns a drawing font from the defaults table.
  429.      *
  430.      * @param key  an Object specifying the font
  431.      * @return the Font object
  432.      */
  433.     public static Font getFont(Object key) { 
  434.         return getDefaults().getFont(key); 
  435.     }
  436.  
  437.     /**
  438.      * Returns a drawing color from the defaults table.
  439.      *
  440.      * @param key  an Object specifying the color
  441.      * @return the Color object
  442.      */
  443.     public static Color getColor(Object key) { 
  444.         return getDefaults().getColor(key); 
  445.     }
  446.  
  447.     /**
  448.      * Returns an Icon from the defaults table.
  449.      *
  450.      * @param key  an Object specifying the icon
  451.      * @return the Icon object
  452.      */
  453.     public static Icon getIcon(Object key) { 
  454.         return getDefaults().getIcon(key); 
  455.     }
  456.  
  457.     /**
  458.      * Returns a border from the defaults table.
  459.      *
  460.      * @param key  an Object specifying the border
  461.      * @return the Border object
  462.      */
  463.     public static Border getBorder(Object key) { 
  464.         return getDefaults().getBorder(key); 
  465.     }
  466.  
  467.     /**
  468.      * Returns a string from the defaults table.
  469.      *
  470.      * @param key  an Object specifying the string
  471.      * @return the String
  472.      */
  473.     public static String getString(Object key) { 
  474.         return getDefaults().getString(key); 
  475.     }
  476.  
  477.     /**
  478.      * Returns an int from the defaults table.
  479.      *
  480.      * @param key  an Object specifying the int
  481.      * @return the int
  482.      */
  483.     public static int getInt(Object key) {
  484.         return getDefaults().getInt(key);
  485.     }
  486.  
  487.     /**
  488.      * Returns an Insets object from the defaults table.
  489.      *
  490.      * @param key  an Object specifying the Insets object
  491.      * @return the Insets object
  492.      */
  493.     public static Insets getInsets(Object key) {
  494.         return getDefaults().getInsets(key);
  495.     }
  496.  
  497.     /**
  498.      * Returns a dimension from the defaults table.
  499.      *
  500.      * @param key  an Object specifying the dimension object
  501.      * @return the Dimension object
  502.      */
  503.     public static Dimension getDimension(Object key) {
  504.         return getDefaults().getDimension(key);
  505.     }
  506.  
  507.     /**
  508.      * Returns an object from the defaults table.
  509.      *
  510.      * @param key  an Object specifying the desired object
  511.      * @return the Object
  512.      */
  513.     public static Object get(Object key) { 
  514.         return getDefaults().get(key); 
  515.     }
  516.  
  517.     /**
  518.      * Stores an object in the defaults table.
  519.      *
  520.      * @param key    an Object specifying the retrieval key
  521.      * @param value  the Object to store
  522.      * @return the Object returned by {@link UIDefaults.put}
  523.      */
  524.     public static Object put(Object key, Object value) { 
  525.         return getDefaults().put(key, value); 
  526.     }
  527.  
  528.     /**
  529.      * Returns the L&F object that renders the target component.
  530.      *
  531.      * @param target  the JComponent to render
  532.      * @return the ComponentUI object that renders the target component
  533.      */
  534.     public static ComponentUI getUI(JComponent target) {
  535.         maybeInitialize();
  536.         ComponentUI ui = null;
  537.         LookAndFeel multiLAF = getLAFState().multiLookAndFeel;
  538.         if (multiLAF != null) {
  539.             // This can return null if the multiplexing look and feel
  540.             // doesn't support a particular UI.
  541.             ui = multiLAF.getDefaults().getUI(target);
  542.         }
  543.         if (ui == null) {
  544.             ui = getDefaults().getUI(target);
  545.         }
  546.         return ui;
  547.     }
  548.  
  549.  
  550.     /**
  551.      * Returns the default values for this look and feel.
  552.      *
  553.      * @return an UIDefaults object containing the default values
  554.      */
  555.     public static UIDefaults getLookAndFeelDefaults() {
  556.         maybeInitialize();
  557.         return getLAFState().getLookAndFeelDefaults();
  558.     }
  559.  
  560.     /**
  561.      * Find the Multiplexing LookAndFeel.
  562.      */
  563.     private static LookAndFeel getMultiLookAndFeel() {
  564.     LookAndFeel multiLookAndFeel = getLAFState().multiLookAndFeel;
  565.     if (multiLookAndFeel == null) {
  566.             String defaultName = "javax.swing.plaf.multi.MultiLookAndFeel";
  567.             String className = getLAFState().swingProps.getProperty(multiplexingLAFKey, defaultName);
  568.             try {
  569.                 Class lnfClass = Class.forName(className);
  570.                 multiLookAndFeel = (LookAndFeel)lnfClass.newInstance();
  571.             } catch (Exception exc) {
  572.                 System.err.println("UIManager: failed loading " + className);
  573.             }
  574.     }
  575.     return multiLookAndFeel;
  576.     }
  577.  
  578.     /**
  579.      * Add a LookAndFeel to the list of auxiliary look and feels.  The
  580.      * auxiliary look and feels tell the multiplexing look and feel what
  581.      * other LookAndFeel classes for a component instance are to be used 
  582.      * in addition to the default LookAndFeel class when creating a 
  583.      * multiplexing UI.  The change will only take effect when a new
  584.      * UI class is created or when the default look and feel is changed
  585.      * on a component instance.
  586.      * <p>Note these are not the same as the installed look and feels.
  587.      *
  588.      * @param laf the LookAndFeel object
  589.      * @see #removeAuxiliaryLookAndFeel
  590.      * @see #setLookAndFeel
  591.      * @see #getAuxiliaryLookAndFeels
  592.      * @see #getInstalledLookAndFeels
  593.      */
  594.     static public void addAuxiliaryLookAndFeel(LookAndFeel laf) 
  595.     {
  596.         maybeInitialize();
  597.  
  598.         Vector v = getLAFState().auxLookAndFeels;
  599.         if (v == null) {
  600.             v = new Vector();
  601.         } 
  602.  
  603.     if (!v.contains(laf)) {
  604.         v.addElement(laf);
  605.             getLAFState().auxLookAndFeels = v;
  606.  
  607.         if (getLAFState().multiLookAndFeel == null) {
  608.             getLAFState().multiLookAndFeel = getMultiLookAndFeel();
  609.             }
  610.     }
  611.     }
  612.  
  613.     /**
  614.      * Remove a LookAndFeel from the list of auxiliary look and feels.  The
  615.      * auxiliary look and feels tell the multiplexing look and feel what
  616.      * other LookAndFeel classes for a component instance are to be used 
  617.      * in addition to the default LookAndFeel class when creating a 
  618.      * multiplexing UI.  The change will only take effect when a new
  619.      * UI class is created or when the default look and feel is changed
  620.      * on a component instance.
  621.      * <p>Note these are not the same as the installed look and feels.
  622.      * @return true if the LookAndFeel was removed from the list
  623.      * @see #removeAuxiliaryLookAndFeel
  624.      * @see #getAuxiliaryLookAndFeels
  625.      * @see #setLookAndFeel
  626.      * @see #getInstalledLookAndFeels
  627.      */
  628.     static public boolean removeAuxiliaryLookAndFeel(LookAndFeel laf) 
  629.     {
  630.         maybeInitialize();
  631.  
  632.     boolean result;
  633.  
  634.         Vector v = getLAFState().auxLookAndFeels;
  635.         if ((v == null) || (v.size() == 0)) {
  636.             return false;
  637.         } 
  638.     
  639.     result = v.removeElement(laf);
  640.     if (result) {
  641.         if (v.size() == 0) {
  642.             getLAFState().auxLookAndFeels = null;
  643.             getLAFState().multiLookAndFeel = null;
  644.         } else {
  645.             getLAFState().auxLookAndFeels = v;
  646.             }
  647.         }
  648.  
  649.     return result;
  650.     }
  651.  
  652.     /**
  653.      * Return the list of auxiliary look and feels (can be null).  The
  654.      * auxiliary look and feels tell the multiplexing look and feel what
  655.      * other LookAndFeel classes for a component instance are to be used 
  656.      * in addition to the default LookAndFeel class when creating a 
  657.      * multiplexing UI.  
  658.      * <p>Note these are not the same as the installed look and feels.
  659.      * @see #addAuxiliaryLookAndFeel
  660.      * @see #removeAuxiliaryLookAndFeel
  661.      * @see #setLookAndFeel
  662.      * @see #getInstalledLookAndFeels
  663.      */
  664.     static public LookAndFeel[] getAuxiliaryLookAndFeels() 
  665.     {
  666.         maybeInitialize();
  667.  
  668.         Vector v = getLAFState().auxLookAndFeels;
  669.         if ((v == null) || (v.size() == 0)) {
  670.             return null;
  671.         } 
  672.         else {
  673.             LookAndFeel[] rv = new LookAndFeel[v.size()];
  674.             for (int i = 0; i < rv.length; i++) {
  675.                 rv[i] = (LookAndFeel)v.elementAt(i);
  676.             }
  677.             return rv;
  678.         }
  679.     }
  680.  
  681.  
  682.     /**
  683.      * Add a PropertyChangeListener to the listener list.
  684.      * The listener is registered for all properties.
  685.      *
  686.      * @param listener  The PropertyChangeListener to be added
  687.      * @see java.beans.PropertyChangeSupport
  688.      */
  689.     public synchronized static void addPropertyChangeListener(PropertyChangeListener listener) 
  690.     {
  691.         getLAFState().changeSupport.addPropertyChangeListener(listener);
  692.     }
  693.  
  694.  
  695.     /**
  696.      * Remove a PropertyChangeListener from the listener list.
  697.      * This removes a PropertyChangeListener that was registered
  698.      * for all properties.
  699.      *
  700.      * @param listener  The PropertyChangeListener to be removed
  701.      * @see java.beans.PropertyChangeSupport
  702.      */
  703.     public synchronized static void removePropertyChangeListener(PropertyChangeListener listener) 
  704.     {
  705.         getLAFState().changeSupport.removePropertyChangeListener(listener);
  706.     }
  707.  
  708.  
  709.     private static Properties loadSwingProperties()
  710.     {
  711.     /* Don't bother checking for Swing properties if untrusted, as
  712.      * there's no way to look them up without triggering SecurityExceptions.
  713.      */
  714.         if (UIManager.class.getClassLoader() != null) {
  715.         return new Properties();
  716.     }
  717.     else {
  718.         final Properties props = new Properties();
  719.  
  720.         SwingUtilities.doPrivileged(new Runnable() {
  721.         public void run() {
  722.             try {
  723.             File file = new File(makeSwingPropertiesFilename());
  724.             BufferedInputStream ins = new BufferedInputStream(new FileInputStream(file));
  725.             props.load(ins);
  726.             ins.close();
  727.             } 
  728.             catch (Exception e) {
  729.             // No such file, or file is otherwise non-readable.
  730.             }
  731.  
  732.             // Check whether any properties were overridden at the
  733.             // command line.
  734.             checkProperty(props, defaultLAFKey);
  735.             checkProperty(props, auxiliaryLAFsKey);
  736.             checkProperty(props, multiplexingLAFKey);
  737.             checkProperty(props, installedLAFsKey);
  738.         }
  739.         });
  740.         return props;
  741.     }
  742.     }
  743.  
  744.     private static void checkProperty(Properties props, String key) {
  745.     try {
  746.         String value = System.getProperty(key);
  747.         if (value != null) {
  748.         props.put(key, value);
  749.         }
  750.     } catch (SecurityException e) {
  751.         // If system won't give us a property, we don't want it!
  752.     }
  753.     }
  754.  
  755.  
  756.     /**
  757.      * If a swing.properties file exist and it has a swing.installedlafs property
  758.      * then initialize the installedLAFs field.
  759.      * 
  760.      * @see #getInstalledLookAndFeels
  761.      */
  762.     private static void initializeInstalledLAFs(Properties swingProps) 
  763.     {
  764.         String ilafsString = swingProps.getProperty(installedLAFsKey);
  765.         if (ilafsString == null) {
  766.             return;
  767.         }
  768.  
  769.         /* Create a vector that contains the value of the swing.installedlafs
  770.          * property.  For example given "swing.installedlafs=motif,windows"
  771.          * lafs = {"motif", "windows"}.
  772.          */
  773.         Vector lafs = new Vector();
  774.         StringTokenizer st = new StringTokenizer(ilafsString, ",", false);
  775.         while (st.hasMoreTokens()) {
  776.             lafs.addElement(st.nextToken());
  777.         }
  778.  
  779.         /* Look up the name and class for each name in the "swing.installedlafs"
  780.          * list.  If they both exist then add a LookAndFeelInfo to 
  781.          * the installedLafs array.
  782.          */
  783.         Vector ilafs = new Vector(lafs.size());
  784.         for(int i = 0; i < lafs.size(); i++) {
  785.             String laf = (String)lafs.elementAt(i);
  786.             String name = swingProps.getProperty(makeInstalledLAFKey(laf, "name"), laf);
  787.             String cls = swingProps.getProperty(makeInstalledLAFKey(laf, "class"));
  788.             if (cls != null) {
  789.                 ilafs.addElement(new LookAndFeelInfo(name, cls));
  790.             }
  791.         }
  792.  
  793.         installedLAFs = new LookAndFeelInfo[ilafs.size()];
  794.         for(int i = 0; i < ilafs.size(); i++) {
  795.             installedLAFs[i] = (LookAndFeelInfo)(ilafs.elementAt(i));
  796.         }
  797.     }
  798.  
  799.  
  800.     /**
  801.      * If the user has specified a default look and feel, use that.  
  802.      * Otherwise use the look and feel that's native to this platform.
  803.      * If this code is called after the application has expclicitly
  804.      * set it's look and feel, do nothing.
  805.      *
  806.      * @see #maybeInitialize
  807.      */
  808.     private static void initializeDefaultLAF(Properties swingProps)
  809.     {
  810.         if (getLAFState().lookAndFeel != null) {
  811.             return;
  812.         }
  813.  
  814.         String metalLnf = getCrossPlatformLookAndFeelClassName();
  815.         String lnfDefault = metalLnf;
  816.  
  817.         String lnfName = "<undefined>" ;
  818.         try {
  819.             lnfName = swingProps.getProperty(defaultLAFKey, lnfDefault);
  820.             setLookAndFeel(lnfName);
  821.         } catch (Exception e) {
  822.             try {
  823.                 lnfName = swingProps.getProperty(defaultLAFKey, metalLnf);
  824.                 setLookAndFeel(lnfName);
  825.             } catch (Exception e2) {
  826.                 throw new Error("can't load " + lnfName);
  827.             }
  828.         }
  829.     }
  830.  
  831.  
  832.     private static void initializeAuxiliaryLAFs(Properties swingProps)
  833.     {
  834.         String auxLookAndFeelNames = swingProps.getProperty(auxiliaryLAFsKey);
  835.         if (auxLookAndFeelNames == null) {
  836.             return;
  837.         }
  838.  
  839.         Vector auxLookAndFeels = new Vector();
  840.  
  841.         StringTokenizer p = new StringTokenizer(auxLookAndFeelNames,",");
  842.         String factoryName;
  843.  
  844.         /* Try to load each LookAndFeel subclass in the list.
  845.          */
  846.  
  847.         while (p.hasMoreTokens()) {
  848.             String className = p.nextToken();
  849.             try {
  850.                 Class lnfClass = Class.forName(className);
  851.                 auxLookAndFeels.addElement(lnfClass.newInstance());
  852.             } 
  853.             catch (Exception e) {
  854.                 System.err.println("UIManager: failed loading auxiliary look and feel " + className);
  855.             }
  856.         }
  857.  
  858.         /* If there were problems and no auxiliary look and feels were 
  859.          * loaded, make sure we reset auxLookAndFeels to null.
  860.          * Otherwise, we are going to use the MultiLookAndFeel to get
  861.          * all component UI's, so we need to load it now.
  862.          */
  863.         if (auxLookAndFeels.size() == 0) {
  864.             auxLookAndFeels = null;
  865.         } 
  866.         else {
  867.         getLAFState().multiLookAndFeel = getMultiLookAndFeel();
  868.         if (getLAFState().multiLookAndFeel == null) {
  869.                 auxLookAndFeels = null;
  870.         }
  871.         }
  872.  
  873.         getLAFState().auxLookAndFeels = auxLookAndFeels;
  874.     }
  875.  
  876.  
  877.     private static void initializeSystemDefaults(Properties swingProps)
  878.     {
  879.         Object defaults[] = {
  880.             "FocusManagerClassName", "javax.swing.DefaultFocusManager"
  881.         };
  882.         getLAFState().setSystemDefaults(new UIDefaults(defaults));
  883.     getLAFState().swingProps = swingProps;
  884.     }
  885.  
  886.  
  887.     private static void initialize()
  888.     {
  889.         Properties swingProps = loadSwingProperties();
  890.     try {
  891.         // We discourage the JIT during UI initialization.
  892.         // JITing here tends to be counter-productive.
  893.         java.lang.Compiler.disable();
  894.  
  895.             initializeSystemDefaults(swingProps);
  896.             initializeDefaultLAF(swingProps);
  897.             initializeAuxiliaryLAFs(swingProps);
  898.             initializeInstalledLAFs(swingProps);
  899.  
  900.     } finally {
  901.         // Make sure to always re-enable the JIT.
  902.         java.lang.Compiler.enable();
  903.     }
  904.     }
  905.  
  906.  
  907.     synchronized private static void maybeInitialize() {
  908.         if (!getLAFState().initialized) {
  909.         synchronized (UIManager.class) {
  910.         // Set flag first so when default LNF initializes it
  911.         // doesn't re-initialize.
  912.         getLAFState().initialized = true;
  913.         initialize();
  914.         }
  915.         }
  916.     }
  917. }
  918.